﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using Haozes.FxClient.Sip;
using Haozes.FxClient.Core;
using Haozes.FxClient.CommUtil;
using System.Diagnostics;
using System.Xml;

namespace Haozes.FxClient
{
    public class Client
    {
        private User user;
        private LoginMgr loginMgr;
        private MessageParser msgParser;
        private ConversationMgr convMgr;
        private bool isAlive = true;

        private Conversation convGetContacts;
        private Conversation convGetPersonalInfo;
        private Conversation convGetContactsInfo;
        //获取单个用户的信息
        private Conversation convGetContactInfo;
        //被添加好友会话
        private Conversation convHandleContactRequest;
        private Conversation convAddBuddy;
        private Conversation convAddMobileBuddy;
        private Conversation convDeleteBuddy;

        public event EventHandler LoginSucceed;
        public event EventHandler LoginFailed;
        //好友列表完全加载成功
        public event EventHandler Load;
        public event EventHandler<ConversationArgs> MsgReceived;
        public event EventHandler<FxErrArgs> Errored;
        //从其他客户端登陆
        public event EventHandler Deregistered;
        //别人添加自己为好友事件
        public event EventHandler<ConversationArgs> AddBuddyRequest;
        //添加别人为好友事件
        public event EventHandler<ConversationArgs> AddBuddyResult;
        public event EventHandler<ConversationArgs> DeleteBuddyResult;

        //private event EventHandler<ConversationArgs> UpdateBuddyRequest;
        public Client()
        {
            ErrManager.Erroring += new EventHandler<FxErrArgs>(this.OnErrored);
        }

        public void Login(string mobile, string pwd)
        {
            this.user = new User(long.Parse(mobile), pwd);
            this.loginMgr = new LoginMgr(this.user);
            this.loginMgr.LoginSucceed += new EventHandler<LoginEventArgs>(this.LoginMgr_LoginSuccess);
            this.loginMgr.LoginFailed += new EventHandler<LoginEventArgs>(this.OnLoginFailed);
            this.loginMgr.Login();
            this.isAlive = true;
        }

        public void Exit()
        {
            if (this.isAlive == false)
                return;
            this.user.Conncetion.Close();
            ErrManager.Erroring -= new EventHandler<FxErrArgs>(this.OnErrored);
            this.loginMgr.LoginSucceed -= new EventHandler<LoginEventArgs>(this.LoginMgr_LoginSuccess);
            this.loginMgr.LoginFailed -= new EventHandler<LoginEventArgs>(this.OnLoginFailed);
            this.isAlive = false;
        }

        private void LoginMgr_LoginSuccess(object sender, LoginEventArgs e)
        {
            DebugWriter.WriteLine("完全登陆成功,开始初始化好友列表!");

            Thread.Sleep(1000);
            PacketFactory.Ower = this.user;
            this.convMgr = new ConversationMgr(this.user.Conncetion);
            this.convMgr.MsgReceived += new EventHandler<ConversationArgs>(this.MsgReceived);
            this.convMgr.Deregistered += new EventHandler(this.Deregistered);
            this.convMgr.AddBuddyRequest += new EventHandler<ConversationArgs>(this.AddBuddyRequest);
            this.convMgr.UpdateBuddyRequest += new EventHandler<ConversationArgs>(this.ConvMgr_UpdateBuddyRequest);

            this.msgParser = new MessageParser(this.convMgr);
            this.user.Conncetion.MessageReceived += new EventHandler<ConversationArgs>(this.msgParser.ReceiveSipMessage);
            this.user.Conncetion.StartListen();

            this.GetPersonalInfo();
            this.GetContacts();

            if (this.LoginSucceed != null)
            {
                this.LoginSucceed(this, null);
            }
        }

        private void ConvMgr_UpdateBuddyRequest(object sender, ConversationArgs e)
        {
            SipUri buddyUri = new SipUri(e.Text);
            if (buddyUri != null)
            {
                e.Text = buddyUri.ToString();
                if (this.AddBuddyResult != null)
                {
                    this.AddBuddyResult(this, e);
                }
                if (buddyUri.ToString().StartsWith("sip:"))
                {
                    this.GetContactInfo(buddyUri);
                }
                else
                {
                    this.user.ContactsManager.Add(new Contact(buddyUri, buddyUri.Sid.ToString(), ContactType.MobileBuddy));
                }
            }
        }

        private void GetPersonalInfo()
        {
            SipMessage getPersonalInfo = PacketFactory.GetPersonalInfo();
            this.convGetPersonalInfo = this.convMgr.Create(getPersonalInfo, true);
            this.convGetPersonalInfo.MsgRcv += new EventHandler<ConversationArgs>(this.ConvGetPersonalInfo_OnMsgRcv);
        }

        //获取联系人列表
        private void GetContacts()
        {
            SipMessage getContactsPackt = PacketFactory.GetContactList();
            this.convGetContacts = this.convMgr.Create(getContactsPackt, true);
            this.convGetContacts.MsgRcv += new EventHandler<ConversationArgs>(this.ConvGetContacts_OnMsgRcv);
        }

        //获取联系人详细信息
        private void GetContactsInfo()
        {
            IList<Contact> buddies = this.user.ContactsManager.GetContactByType(this.user.Contacts, ContactType.Buddy);
            if (buddies.Count > 0)
            {
                SipMessage getContactsInfoPacket = PacketFactory.GetContactsInfo(buddies);
                this.convGetContactsInfo = this.convMgr.Create(getContactsInfoPacket, true);
                this.convGetContactsInfo.MsgRcv += new EventHandler<ConversationArgs>(this.ConvGetContactsInfo_OnMsgRcv);
            }
        }

        private void ConvGetPersonalInfo_OnMsgRcv(object sender, ConversationArgs e)
        {
            this.user.CreatePersonalInfo(e.Text);
            this.convGetPersonalInfo.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvGetPersonalInfo_OnMsgRcv);
            this.convMgr.Remove(this.convGetPersonalInfo.CallID);
        }

        private void ConvGetContacts_OnMsgRcv(object sender, ConversationArgs e)
        {
            this.user.ContactsManager.InitContactList(e.Text);
            this.convGetContacts.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvGetContacts_OnMsgRcv);
            this.convMgr.Remove(this.convGetContacts.CallID);
            if (this.user.Contacts.Count == 0)
            {
                if (this.Load != null)
                {
                    this.Load(this, null);
                }
            }
            else
            {
                this.GetContactsInfo();
            }
        }

        private void ConvGetContactsInfo_OnMsgRcv(object sender, ConversationArgs e)
        {
            if (e.Text.IndexOf("status-code") >= 0)
            {
                this.user.ContactsManager.GetContactsInfo(this.user.Contacts, e.Text);
                if (this.user.ContactsManager.IsCompleted())
                { //此时联系人加载完毕
                    if (this.Load != null)
                    {
                        this.Load(this, null);
                    }
                    this.convGetContactsInfo.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvGetContactsInfo_OnMsgRcv);
                    this.convMgr.Remove(this.convGetContactsInfo.CallID);
                }
            }
        }

        protected virtual void OnLoginFailed(object sender, LoginEventArgs e)
        {
            if (this.LoginFailed != null)
            {
                this.LoginFailed(this, null);
                this.Log.Error(e.ToString());
            }
        }

        protected virtual void OnErrored(object sender, FxErrArgs e)
        {
            if (this.Errored != null)
            {
                this.Errored(this, e);
            }
            this.Log.Error(e.ToString());
        }

        public bool IsALive
        {
            get { return this.isAlive; }
            set { this.isAlive = value; }
        }

        public log4net.ILog Log
        {
            get { return LogUtil.Log; }
            set { LogUtil.Init(value); }
        }

        public User CurrentUser
        {
            get { return this.user; }
        }

        public void Send(Conversation conv, string content)
        {
            if (this.convMgr.HasConversation(conv))
            {
                conv.SendMsg(content);
            }
            else
            {
                this.SendSMS(conv.From, content);
            }
        }

        public void SendMsg(SipUri uri, string content)
        {
            this.convMgr.SendMsg(uri, content);
        }

        public void SendMsg(SipMessage rcvPacket, string msgContent)
        {
            this.convMgr.SendMsg(rcvPacket, msgContent);
        }
        public void SendSMS(SipUri uri, string content)
        {
            this.convMgr.SendSMS(uri, content);
        }

        public void SendToSelf(string content)
        {
            this.convMgr.SendSMS(this.CurrentUser.Uri, content);
        }

        /// <summary>
        /// 添加好友
        /// </summary>
        /// <param name="uri">sipuri</param>
        /// <param name="desc">description,为空时显示用户昵称</param>
        public void AddBuddy(SipUri uri, string desc)
        {
            if (this.isAlive == false)
                return;
            SipMessage packet = PacketFactory.AddBuddy(uri, desc);
            this.convAddBuddy = this.convMgr.Create(packet, true);
            this.convAddBuddy.MsgRcv += new EventHandler<ConversationArgs>(this.ConvAddBuddy_MsgRcv);
        }

        private void ConvAddBuddy_MsgRcv(object sender, ConversationArgs e)
        {
            SipMessage sipMsg = e.RawPacket;
            SipResponse rsp = sipMsg as SipResponse;
            string resultText = string.Empty;

            if (rsp != null)
            {
                this.Log.Debug(string.Format("addbuddy result:{0}", e.RawPacket));
                if (rsp.StatusCode == 200)
                {
                    string rspContent = e.Text;
                    XmlDocument document = new XmlDocument();
                    document.LoadXml(rspContent);
                    XmlNode node = document.SelectSingleNode("results/contacts/buddies/buddy");
                    string uri = XmlHelper.ReadXmlAttributeString(node, "uri");
                    //把对方的Uri传回去
                    resultText = uri;
                }
                else if (rsp.StatusCode == 522)
                { //not a fetion buddy
                    this.Log.Debug(string.Format("addbuddy:not a fetion buddy,the reasonPhrase is:{0}", rsp.ReasonPhrase));
                    if (e.OriginPacket != null)
                    {
                        string originBody = e.OriginPacket.Body;
                        XmlDocument document = new XmlDocument();
                        document.LoadXml(originBody);
                        XmlNode node = document.SelectSingleNode("args/contacts/buddies/buddy");
                        string uri = XmlHelper.ReadXmlAttributeString(node, "uri");
                        string desc = XmlHelper.ReadXmlAttributeString(node, "desc");
                        this.AddMobileBuddy(new SipUri(uri), desc);
                        this.convAddBuddy.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvAddBuddy_MsgRcv);
                        return; //here use  AddMobileBuddy method instead
                    }
                }
                else
                { //can't add this buddy
                    if (this.AddBuddyResult != null)
                    {
                        ConversationArgs resultArg = new ConversationArgs(IMType.AddBuddyResult, rsp);
                        resultArg.Text = string.Empty;
                        this.AddBuddyResult(this, resultArg);
                        this.convAddBuddy.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvAddBuddy_MsgRcv);
                    }
                }
            }
        }

        private void AddMobileBuddy(SipUri uri, string desc)
        {
            SipMessage packet = PacketFactory.AddMobileBuddy(uri, desc);
            this.convAddMobileBuddy = this.convMgr.Create(packet, true);
            this.convAddMobileBuddy.MsgRcv += new EventHandler<ConversationArgs>(this.ConvAddMobileBuddy_MsgRcv);
        }

        private void ConvAddMobileBuddy_MsgRcv(object sender, ConversationArgs e)
        {
            SipMessage sipMsg = e.RawPacket;
            SipResponse rsp = sipMsg as SipResponse;
            string resultText = string.Empty;
            if (rsp != null)
            {
                this.Log.Debug(string.Format("addbuddy result:{0}", e.RawPacket));
                if (rsp.StatusCode == 200)
                {
                    string rspContent = e.Text;
                    XmlDocument document = new XmlDocument();
                    document.LoadXml(rspContent);
                    XmlNode node = document.SelectSingleNode("results/contacts/mobile-buddies/mobile-buddy");
                    string uri = XmlHelper.ReadXmlAttributeString(node, "uri");
                    resultText = uri;
                }
                if (this.AddBuddyResult != null)
                {
                    ConversationArgs resultArg = new ConversationArgs(IMType.AddBuddyResult, rsp);
                    resultArg.Text = resultText;
                    this.AddBuddyResult(this, resultArg);
                    this.convAddMobileBuddy.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvAddMobileBuddy_MsgRcv);
                }
            }
        }

        public void GetContactInfo(SipUri uri)
        {
            SipMessage packet = PacketFactory.GetContactsInfo(uri);
            this.convGetContactInfo = this.convMgr.Create(packet, true);
            this.convGetContactInfo.MsgRcv += new EventHandler<ConversationArgs>(this.ConvGetContactInfo_MsgRcv);
        }

        private void ConvGetContactInfo_MsgRcv(object sender, ConversationArgs e)
        {
            XmlDocument document = new XmlDocument();
            document.LoadXml(e.Text);
            XmlNode node = document.SelectSingleNode("results/contacts/contact");
            if (node != null)
            {
                string statu = XmlHelper.ReadXmlAttributeString(node, "status-code");
                if (statu == "200")
                {
                    this.user.SaveOrUpdateContactInfo(e.Text);
                }
                else
                {
                    this.Log.Info("获取不到该好友详细信息");
                }
                this.convGetContactInfo.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvGetContactInfo_MsgRcv);
            }
        }
        // 同意对方添加自己为好友
        public void AgreeAddBuddy(SipUri uri)
        {
            SipMessage agreePacket = PacketFactory.HandleContactRequest(uri);
            this.convHandleContactRequest = this.convMgr.Create(agreePacket, true);
            this.convHandleContactRequest.MsgRcv += new EventHandler<ConversationArgs>(this.ConvHandleContactRequest_MsgRcv);
        }

        private void ConvHandleContactRequest_MsgRcv(object sender, ConversationArgs e)
        {
            if (e.Text.IndexOf("BuddyPermissionChanged") >= 0)
            {
                try
                {
                    XmlDocument document = new XmlDocument();
                    document.LoadXml(e.Text);
                    XmlNode node = document.SelectSingleNode("events/event/permissions/permission");
                    string uri = XmlHelper.ReadXmlAttributeString(node, "uri");
                    SipUri sipUri = new SipUri(uri);
                    this.GetContactInfo(sipUri);
                }
                catch (Exception ex)
                {
                    ErrManager.RaiseError(new FxErrArgs(ex));
                }
                this.convHandleContactRequest.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvHandleContactRequest_MsgRcv);
            }
        }

        public void DeleteBuddy(SipUri buddyUri)
        {
            SipMessage deletePacket = null;
            if (buddyUri.ToString().StartsWith("sip"))
            {
                deletePacket = PacketFactory.DeleteBuddy(buddyUri);
            }
            else
            {
                deletePacket = PacketFactory.DeleteMobileBuddy(buddyUri);
            }
            this.convDeleteBuddy = this.convMgr.Create(deletePacket, true);
            this.convDeleteBuddy.MsgRcv += new EventHandler<ConversationArgs>(this.ConvDeleteBuddy_MsgRcv);
        }

        private void ConvDeleteBuddy_MsgRcv(object sender, ConversationArgs e)
        {
            SipResponse rsp = e.RawPacket as SipResponse;
            if (rsp != null)
            {
                XmlDocument document = new XmlDocument();
                document.LoadXml(rsp.Body);
                XmlNode node = document.SelectSingleNode("results/contacts/buddies/buddy");
                if (node != null)
                {
                    string uri = XmlHelper.ReadXmlAttributeString(node, "uri");
                    if (!string.IsNullOrEmpty(uri))
                    {
                        this.user.ContactsManager.Delete(new SipUri(uri));
                    }
                }
                ConversationArgs resultArg = new ConversationArgs(IMType.DeleteBuddyResult, rsp);
                resultArg.Text = rsp.StatusCode.ToString();
                this.DeleteBuddyResult(this, resultArg);
                this.convDeleteBuddy.MsgRcv -= new EventHandler<ConversationArgs>(this.ConvDeleteBuddy_MsgRcv);
            }
        }
    }
}
